Skip to content

feat(dns): manage Scriptable DNS scripts with ambient runtime types#104

Open
jamie-at-bunny wants to merge 4 commits into
mainfrom
feat/dns-scriptable-scripts
Open

feat(dns): manage Scriptable DNS scripts with ambient runtime types#104
jamie-at-bunny wants to merge 4 commits into
mainfrom
feat/dns-scriptable-scripts

Conversation

@jamie-at-bunny

Copy link
Copy Markdown
Member

No description provided.

@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6464333

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@bunny.net/cli Patch
@bunny.net/scriptable-dns-types Patch
@bunny.net/cli-linux-x64 Patch
@bunny.net/cli-linux-arm64 Patch
@bunny.net/cli-darwin-x64 Patch
@bunny.net/cli-darwin-arm64 Patch
@bunny.net/cli-windows-x64 Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@jamie-at-bunny jamie-at-bunny marked this pull request as ready for review June 25, 2026 14:15
@bogdan-at-bunny

Copy link
Copy Markdown

@codex review

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds Scriptable DNS management to the CLI. The main changes are:

  • New bunny dns scripts commands for init, create, deploy, attach, link, and list.
  • Interactive DNS record creation can choose a script-computed answer.
  • A new @bunny.net/scriptable-dns-types package provides ambient runtime types.
  • Documentation and workspace metadata were updated for the new package and commands.

Confidence Score: 4/5

This is close, but I would fix the type declaration before merging.

  • The new command wiring and DNS record payloads follow the existing CLI patterns.
  • The new ambient runtime package can reject valid health-routing script code during the scaffolded typecheck.

packages/scriptable-dns-types/index.d.ts

Important Files Changed

Filename Overview
packages/cli/src/commands/dns/scripts/api.ts Adds shared compute API helpers used by the new DNS script commands.
packages/cli/src/commands/dns/record/add.ts Adds the interactive script-computed answer path for DNS records.
packages/cli/src/commands/dns/scripts/attach.ts Adds SCRIPT record attachment from the DNS script command group.
packages/cli/src/commands/dns/scripts/init.ts Scaffolds local Scriptable DNS projects with starter code and typecheck setup.
packages/scriptable-dns-types/index.d.ts Adds ambient runtime declarations for Scriptable DNS scripts.

Fix All in Claude Code

Reviews (3): Last reviewed commit: "static-vs-scriptable" | Re-trigger Greptile

action: string,
interactive: boolean,
): Promise<number> {
if (id) return id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Invalid ID Falls Back

When a non-numeric positional id is passed, yargs can provide NaN, and this truthiness check treats it as omitted. deploy or attach can then use the linked manifest or picker instead of rejecting the bad id, so a typo can target the wrong DNS script.

Suggested change
if (id) return id;
if (id !== undefined) {
if (!Number.isFinite(id)) {
throw new UserError("DNS script ID must be a number.");
}
return id;
}

Context Used: CLAUDE.md (source)

Fix in Claude Code

Comment on lines +25 to +27
const { data } = await client.GET("/compute/script", {
params: { query: { type: [SCRIPT_TYPE_DNS] } },
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Script List Drops Later Pages

The compute script list endpoint is paginated, but this call only reads the first page. Accounts past the API page size will see incomplete dns scripts list output, and interactive deploy or attach pickers will omit valid DNS scripts unless the id is entered manually.

Context Used: CLAUDE.md (source)

Fix in Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9171b922fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

file = value;
}
file ??= defaultFile;
const absPath = resolve(file);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve default entry relative to the linked project

Because loadManifest() walks up to a parent .bunny/dns-script.json, a linked DNS script can be resolved while the process is in a subdirectory of the scaffolded project. The default entry stored by init is relative to that project root, but this resolves it against the current subdirectory, so bunny dns scripts deploy from src/ looks for src/handleQuery.js and fails with “File not found” even though the linked project has handleQuery.js at its root.

Useful? React with 👍 / 👎.

Comment on lines +140 to +146
type DnsAnswer =
| ARecord
| AaaaRecord
| CnameRecord
| TxtRecord
| PullZoneRecord
| Server;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Allow array responses in DnsAnswer

The Scriptable DNS docs allow returning an array of response objects, but this ambient DnsAnswer only permits a single object. Any user who annotates handleQuery with DnsAnswer and returns multiple A/CNAME/etc. records will fail the scaffolded tsc --noEmit check even though the script is valid at runtime; include array responses in this type.

Useful? React with 👍 / 👎.

entry: DEFAULT_ENTRY,
});
logger.success(`Created DNS script "${created.name}" (${created.id}).`);
} catch (err: unknown) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when explicit DNS script creation fails

When bunny dns scripts init ... --deploy is used by automation, this catch converts any config/API failure from creating the remote script into a warning and the command continues to emit successful JSON/exit 0 with no script. Callers that requested deployment will proceed without a remote script or manifest id, so explicit --deploy failures should be rethrown or returned as a nonzero JSON error while preserving the interactive warning path.

Useful? React with 👍 / 👎.

Comment on lines +25 to +27
const { data } = await client.GET("/compute/script", {
params: { query: { type: [SCRIPT_TYPE_DNS] } },
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Page through all DNS scripts

The compute list endpoint is paginated, but this helper only issues one GET with the DNS type filter. Accounts with more scripts than the first page will have dns scripts list, the attach picker, and the interactive SCRIPT-record picker silently omit valid scripts, so loop until HasMoreItems is false as the DNS zone helper does.

Useful? React with 👍 / 👎.

action: string,
interactive: boolean,
): Promise<number> {
if (id) return id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate explicit DNS script IDs before deploying

When a user passes an explicit ID, this path returns it without checking that the target script is actually ScriptType: DNS. bunny dns scripts deploy handleQuery.js <id> can therefore upload and publish DNS handler code over an existing CDN or Middleware Edge Script if the wrong ID is supplied; fetch the script and reject non-DNS types before allowing deploy/attach operations to continue.

Useful? React with 👍 / 👎.

Comment on lines +17 to +18
if (!data) throw new UserError(`DNS script ${id} not found.`);
return data;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Validate Script Type

fetchDnsScript only checks that the compute script exists. dns scripts link <id> can therefore write a regular Edge Script id into .bunny/dns-script.json, and later dns scripts deploy will upload DNS code to that non-DNS script while dns scripts attach can create a SCRIPT record pointing at it. The helper should reject scripts whose ScriptType is not SCRIPT_TYPE_DNS before callers treat the id as a Scriptable DNS script.

Fix in Claude Code

latitude?: number,
longitude?: number,
weight?: number,
online?: boolean,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Expose Server State

The Server constructor accepts an online flag, and RoutingEngine has onlineOnly modes, but the instance type does not expose online. In a scaffolded project, checkJs: true means valid Scriptable DNS code such as filtering servers by server.online fails typecheck even though the runtime object was constructed with that state. Add the property so custom health-routing scripts can typecheck against the declared runtime shape.

Fix in Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants